package com.spring.theory.aop;

import java.lang.reflect.Method;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * CglibProxy 基本使用
 * - 基于父子关系的代理
 *
 * @author H
 * @version 1.0
 * @date 2023-12-29 16:54
 */
@Slf4j
public class CglibProxy {

    /**
     * 父类及父类方法不能是 final
     * - 本质是通过重写去增加逻辑
     * - 父类方法加 final ，运行不报错，但会没有逻辑增强的部分
     */
    static class Target {
        public void cglibProxyTest(String name) {
            log.info("cglib target test...method:{}", name);
        }
    }

    public static void main(String[] args) {
        Target target = new Target();
        /**
         * 代理类与目标类是子父关系；本质是通过重写去增加逻辑
         */
        Target proxyCg = (Target) Enhancer.create(Target.class, new MethodInterceptor() {
            /**
             * object：代理对象本身；
             * method：正在执行的方法对象；
             * objects：方法传来的实际参数；
             * methodProxy：代理对象的方法对象
             */
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                log.info("cglib proxy...before");
                /**
                 * 1. 方法反射调用目标
                 */
                //Object result = method.invoke(target, args);
                /**
                 * 2. methodProxy可以避免反射调用；内部没有反射；需要目标 [Spring使用这种方式]
                 */
                Object result = methodProxy.invoke(target, args);
                /**
                 * 3. 需要代理对象本身；内部没有反射
                 */
                //Object result = methodProxy.invokeSuper(o, args);
                log.info("cglib proxy...after");
                return result;
            }
        });
        proxyCg.cglibProxyTest("cglib proxy");
    }

}
